package com.vic.mvc.framework.util;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ClassUtil {
	
	 /**
     * 根据注解和scannerPackage 获得Class
     * @param scannerPackage
     * @param annotationClass
     * @return
     */
	public static List<Class<?>> getClassByAnnotation(String scannerPackage, Class<? extends Annotation> annotationClass) {
		List<Class<?>> list = new ArrayList<Class<?>>();
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		try {
			Enumeration<URL> urls =  classLoader.getResources(scannerPackage.replaceAll("\\.", "/"));
			while(urls.hasMoreElements()) {
				URL url = urls.nextElement();
				if(url != null) {
					String protocol = url.getProtocol();//资源类型
					if("file".equals(protocol)) {//class文件
						String packagePath = url.getPath();
						addClassByAnnotation(list, packagePath, scannerPackage, annotationClass);
					}else if("jar".equals(protocol)) {
						JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
						JarFile jarFile = jarURLConnection.getJarFile();
						Enumeration<JarEntry> jarEntries = jarFile.entries();
						while(jarEntries.hasMoreElements()) {
							JarEntry jarEntry = jarEntries.nextElement();
							String jarEntryName = jarEntry.getName();// 类似：sun/security/internal/interfaces/TlsMasterSecret.class
							if(jarEntryName.endsWith(".class") ) {
								String className = jarEntryName.substring(0,  jarEntryName.lastIndexOf(".")).replace("/", ".");
								Class<?> clazz = Class.forName(className);
								if(clazz.isAnnotationPresent(annotationClass)) {
									list.add(clazz);
								}
							}
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return list;
	}


	/**
	 * 获得annotationClass注解的class
	 * @param packagePath 文件路径
	 * @param packageName 扫描的根包
	 * @param annotationClass 注解
	 */
	private static void addClassByAnnotation(List<Class<?>> list, String packagePath, String packageName,
			Class<? extends Annotation> annotationClass) {
		try{
			File[] files = getClassFiles(packagePath);
			if(files != null && files.length > 0) {
				for(File file : files) {
					String fileName = file.getName();
					if(file.isFile()) {//如果是.class文件
						String className = getClassName(packageName, fileName);
						Class<?> clazz = Class.forName(className);
						if(clazz.isAnnotationPresent(annotationClass)){
							list.add(clazz);
						}
					}else {//如果是类文件夹
						String subPackagePath = getSubPackagePath(packagePath, fileName);
						String subPackageName = getSubPackageName(packageName, fileName);
						addClassByAnnotation(list, subPackagePath, subPackageName, annotationClass);
					}
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	/**
	 *获得子包包名 
	 */
	private static String getSubPackageName(String packageName, String fileName) {
		if(StringUtil.isNotEmpty(packageName)) {
			return packageName + "." + fileName;
		}
		return fileName;
	}


	/**
	 * 获取子文件的路径
	 */
	private static String getSubPackagePath(String packagePath, String filePath) {
		if(StringUtil.isNotEmpty(packagePath)) {
			return packagePath + "/" + filePath;
		}
		return filePath;
	}


	/**
	 * 获取路径下的全部.class文件或类文件夹
	 */
	private static File[] getClassFiles(String packagePath) {
		return new File(packagePath).listFiles(new FileFilter() {
			@Override
			public boolean accept(File file) {
				return file.isFile() && file.getName().endsWith(".class") || file.isDirectory();
			}
		});
	}  
	 //去掉绝对路劲中class后缀   
    private static String getClassName(String pkgName, String fileName) {  
    	String clazzName = fileName.substring(0, fileName.lastIndexOf("."));
    	if(StringUtil.isNotEmpty(pkgName)) {
    		clazzName = pkgName + "." + clazzName;
    	}
        return clazzName;  
    }  
    
    
    private static void addClassName(List<Class<?>> clazzList, String clazzName, Class<? extends Annotation> annotation) {  
		try {
			Class<?> clazz = Class.forName(clazzName);
			if (clazz.isAnnotationPresent(annotation)){  
				clazzList.add(clazz);  
			}  
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}  
    }

    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
	
	/***************************************************************/
	
	
	
	

	public static List<Class<?>> getClassList(String pkgName , boolean isRecursive, Class<? extends Annotation> annotation){
		List<Class<?>> classList = new ArrayList<Class<?>>();
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		String filePath = pkgName .replace("\\.", "/");
		try {
			Enumeration<URL> urls = loader.getResources(filePath);
			while(urls.hasMoreElements()) {
				URL url = urls.nextElement();
				if(url != null) {
					String protocol = url.getProtocol();
					String path = url.getPath();
					System.out.println("protocol:" + protocol +" path:" + path);
					if("file".equals(protocol)) {
						 // 本地自己可见的代码  
                        findClassName(classList, pkgName, path, isRecursive, annotation);  
					}else if("jar".equals(protocol)) {
						 findClassName(classList, pkgName, url, isRecursive, annotation);  
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return classList;
	}
	
	
	  public static void findClassName(List<Class<?>> clazzList, String pkgName, String pkgPath, boolean isRecursive, Class<? extends Annotation> annotation) {  
	        if(clazzList == null){  
	            return;  
	        }  
	        File[] files = filterClassFiles(pkgPath);// 过滤出.class文件及文件夹  
	        System.out.println("files:" +((files == null)?"null" : "length=" + files.length));  
	        if(files != null){  
	            for (File f : files) {  
	                String fileName = f.getName();  
	                if (f.isFile()) {  
	                    // .class 文件的情况  
	                    String clazzName = getClassName(pkgName, fileName);  
	                    addClassName(clazzList, clazzName, annotation);  
	                } else {  
	                    // 文件夹的情况  
	                    if(isRecursive){  
	                        // 需要继续查找该文件夹/包名下的类  
	                        String subPkgName = pkgName +"."+ fileName;  
	                        String subPkgPath = pkgPath +"/"+ fileName;  
	                        findClassName(clazzList, subPkgName, subPkgPath, true, annotation);  
	                    }  
	                }  
	            }  
	        }  
	    }  
	      
	    /** 
	     * 第三方Jar类库的引用。<br/> 
	     * @throws IOException  
	     * */  
	    public static void findClassName(List<Class<?>> clazzList, String pkgName, URL url, boolean isRecursive, Class<? extends Annotation> annotation) throws IOException {  
	        JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();  
	        JarFile jarFile = jarURLConnection.getJarFile();  
	        System.out.println("jarFile:" + jarFile.getName());  
	        Enumeration<JarEntry> jarEntries = jarFile.entries();  
	        while (jarEntries.hasMoreElements()) {  
	            JarEntry jarEntry = jarEntries.nextElement();  
	            String jarEntryName = jarEntry.getName(); // 类似：sun/security/internal/interfaces/TlsMasterSecret.class  
	            String clazzName = jarEntryName.replace("/", ".");  
	            int endIndex = clazzName.lastIndexOf(".");  
	            String prefix = null;  
	            if (endIndex > 0) {  
	                String prefix_name = clazzName.substring(0, endIndex);  
	                endIndex = prefix_name.lastIndexOf(".");  
	                if(endIndex > 0){  
	                    prefix = prefix_name.substring(0, endIndex);  
	                }  
	            }  
	            if (prefix != null && jarEntryName.endsWith(".class")) {  
//	              System.out.println("prefix:" + prefix +" pkgName:" + pkgName);  
	                if(prefix.equals(pkgName)){  
	                    System.out.println("jar entryName:" + jarEntryName);  
	                    addClassName(clazzList, clazzName, annotation);  
	                } else if(isRecursive && prefix.startsWith(pkgName)){  
	                    // 遍历子包名：子类  
	                    System.out.println("jar entryName:" + jarEntryName +" isRecursive:" + isRecursive);  
	                    addClassName(clazzList, clazzName, annotation);  
	                }  
	            }  
	        }  
	    }  
	      
	    private static File[] filterClassFiles(String pkgPath) {  
	        if(pkgPath == null){  
	            return null;  
	        }  
	        // 接收 .class 文件 或 类文件夹  
	        return new File(pkgPath).listFiles();  
	    }  
	      
	      
	   
	 
	
	
}
